﻿using Sys.Workflow.Bpmn.Models;
using Sys.Workflow.Engine.Impl;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;

namespace Sys.Workflow.Engine.impl.runtime
{
    /* Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing perobjectmissions and
     * limitations under the License.
     */

    /**
     * @author Tijs Rademakers
     */
    public class ChangeActivityStateBuilderImpl : ChangeActivityStateBuilder
    {

        protected RuntimeServiceImpl runtimeService;

        protected String processInstanceId;
        protected List<MoveExecutionIdContainer> moveExecutionIdList = new List<MoveExecutionIdContainer>();
        protected List<MoveActivityIdContainer> moveActivityIdList = new List<MoveActivityIdContainer>();
        protected List<EnableActivityIdContainer> enableActivityIdList = new List<EnableActivityIdContainer>();
        protected Dictionary<string, object> processVariables = new Dictionary<string, object>();
        protected Dictionary<string, Dictionary<string, object>> localVariables = new Dictionary<string, Dictionary<string, object>>();

        public ChangeActivityStateBuilderImpl()
        {
        }
        public ChangeActivityStateBuilderImpl(RuntimeServiceImpl runtimeService)
        {
            this.runtimeService = runtimeService;
        }
        public ChangeActivityStateBuilderImpl(IRuntimeService runtimeService)
        {
            this.runtimeService = (RuntimeServiceImpl)runtimeService;
        }

        /// <summary>
        /// Sets the process instance id for the change activity state builder.
        /// </summary>
        /// <param name="processInstanceId"></param>
        /// <returns></returns>
        public ChangeActivityStateBuilder SetProcessInstanceId(string processInstanceId)
        {
            this.processInstanceId = processInstanceId;
            return this;
        }


        public ChangeActivityStateBuilder MoveExecutionToActivityId(string executionId, string activityId)
        {
            return MoveExecutionToActivityId(executionId, activityId, null, null);
        }

        public ChangeActivityStateBuilder MoveExecutionToActivityId(string executionId, string activityId, string newAssigneeId, string newOwnerId)
        {
            moveExecutionIdList.Add(new MoveExecutionIdContainer(executionId, activityId, newAssigneeId, newOwnerId));
            return this;
        }


        public ChangeActivityStateBuilder MoveExecutionsToSingleActivityId(List<string> executionIds, string activityId)
        {
            return MoveExecutionsToSingleActivityId(executionIds, activityId, null, null);
        }

        public ChangeActivityStateBuilder MoveExecutionsToSingleActivityId(List<string> executionIds, string activityId, string newAssigneeId, string newOwnerId)
        {
            moveExecutionIdList.Add(new MoveExecutionIdContainer(executionIds, activityId, newAssigneeId, newOwnerId));
            return this;
        }


        public ChangeActivityStateBuilder MoveSingleExecutionToActivityIds(string executionId, List<string> activityIds)
        {
            return MoveSingleExecutionToActivityIds(executionId, activityIds, null, null);
        }

        public ChangeActivityStateBuilder MoveSingleExecutionToActivityIds(string executionId, List<string> activityIds, string newAssigneeId, string newOwnerId)
        {
            moveExecutionIdList.Add(new MoveExecutionIdContainer(executionId, activityIds, newAssigneeId, newOwnerId));
            return this;
        }


        public ChangeActivityStateBuilder MoveActivityIdTo(string currentActivityId, string newActivityId)
        {
            return MoveActivityIdTo(currentActivityId, newActivityId, null, null);
        }

        public ChangeActivityStateBuilder MoveActivityIdTo(string currentActivityId, string newActivityId, string? newAssigneeId, string? newOwnerId)
        {
            moveActivityIdList.Add(new MoveActivityIdContainer(currentActivityId, newActivityId, newAssigneeId, newOwnerId));
            return this;
        }


        public ChangeActivityStateBuilder MoveActivityIdsToSingleActivityId(List<string> activityIds, string activityId)
        {
            return MoveActivityIdsToSingleActivityId(activityIds, activityId, null, null);
        }

        public ChangeActivityStateBuilder MoveActivityIdsToSingleActivityId(List<string> activityIds, string activityId, string newAssigneeId, string newOwnerId)
        {
            moveActivityIdList.Add(new MoveActivityIdContainer(activityIds, activityId, newAssigneeId, newOwnerId));
            return this;
        }

        public ChangeActivityStateBuilder MoveSingleActivityIdToActivityIds(string currentActivityId, List<string> newActivityIds)
        {
            return MoveSingleActivityIdToActivityIds(currentActivityId, newActivityIds, null, null);
        }

        public ChangeActivityStateBuilder MoveSingleActivityIdToActivityIds(string currentActivityId, List<string> newActivityIds, string newAssigneeId, string newOwnerId)
        {
            moveActivityIdList.Add(new MoveActivityIdContainer(currentActivityId, newActivityIds, newAssigneeId, newOwnerId));
            return this;
        }


        public ChangeActivityStateBuilder MoveActivityIdToParentActivityId(string currentActivityId, string newActivityId)
        {
            return MoveActivityIdToParentActivityId(currentActivityId, newActivityId, null, null);
        }

        public ChangeActivityStateBuilder MoveActivityIdToParentActivityId(string currentActivityId, string newActivityId, string newAssigneeId, string newOwnerId)
        {
            MoveActivityIdContainer moveActivityIdContainer = new MoveActivityIdContainer(currentActivityId, newActivityId, newAssigneeId, newOwnerId);
            moveActivityIdContainer.SetMoveToParentProcess(true);
            moveActivityIdList.Add(moveActivityIdContainer);
            return this;
        }

        public ChangeActivityStateBuilder MoveActivityIdsToParentActivityId(List<string> currentActivityIds, string newActivityId, string newAssigneeId, string newOwnerId)
        {
            MoveActivityIdContainer moveActivityIdContainer = new MoveActivityIdContainer(currentActivityIds, newActivityId, newAssigneeId, newOwnerId);
            moveActivityIdContainer.SetMoveToParentProcess(true);
            moveActivityIdList.Add(moveActivityIdContainer);
            return this;
        }

        public ChangeActivityStateBuilder MoveSingleActivityIdToParentActivityIds(string currentActivityId, List<string> newActivityIds)
        {
            MoveActivityIdContainer moveActivityIdContainer = new MoveActivityIdContainer(currentActivityId, newActivityIds);
            moveActivityIdContainer.SetMoveToParentProcess(true);
            moveActivityIdList.Add(moveActivityIdContainer);
            return this;
        }

        public ChangeActivityStateBuilder MoveActivityIdToSubProcessInstanceActivityId(string currentActivityId, string newActivityId, string callActivityId)
        {
            return MoveActivityIdToSubProcessInstanceActivityId(currentActivityId, newActivityId, callActivityId, long.MinValue, null, null);
        }


        public ChangeActivityStateBuilder MoveActivityIdToSubProcessInstanceActivityId(string currentActivityId, string newActivityId, string callActivityId, long subProcessDefinitionVersion)
        {
            return MoveActivityIdToSubProcessInstanceActivityId(currentActivityId, newActivityId, callActivityId, subProcessDefinitionVersion, null, null);
        }

        public ChangeActivityStateBuilder MoveActivityIdToSubProcessInstanceActivityId(string currentActivityId, string newActivityId, string callActivityId, long callActivitySubProcessVersion, string newAssigneeId, string newOwnerId)
        {
            MoveActivityIdContainer moveActivityIdContainer = new MoveActivityIdContainer(currentActivityId, newActivityId, newAssigneeId, newOwnerId);
            moveActivityIdContainer.SetMoveToSubProcessInstance(true);
            moveActivityIdContainer.SetCallActivityId(callActivityId);
            moveActivityIdContainer.SetCallActivitySubProcessVersion(callActivitySubProcessVersion);
            moveActivityIdList.Add(moveActivityIdContainer);
            return this;
        }

        public ChangeActivityStateBuilder MoveActivityIdsToSubProcessInstanceActivityId(List<string> activityIds, string newActivityId, string callActivityId,
                long callActivitySubProcessVersion, string newAssigneeId, string newOwnerId)
        {
            MoveActivityIdContainer moveActivityIdsContainer = new MoveActivityIdContainer(activityIds, newActivityId, newAssigneeId, newOwnerId);
            moveActivityIdsContainer.SetMoveToSubProcessInstance(true);
            moveActivityIdsContainer.SetCallActivityId(callActivityId);
            moveActivityIdsContainer.SetCallActivitySubProcessVersion(callActivitySubProcessVersion);
            moveActivityIdList.Add(moveActivityIdsContainer);
            return this;
        }

        public ChangeActivityStateBuilder MoveSingleActivityIdToSubProcessInstanceActivityIds(string currentActivityId, List<string> newActivityIds, string callActivityId, long callActivitySubProcessVersion)
        {
            MoveActivityIdContainer moveActivityIdsContainer = new MoveActivityIdContainer(currentActivityId, newActivityIds);
            moveActivityIdsContainer.SetMoveToSubProcessInstance(true);
            moveActivityIdsContainer.SetCallActivityId(callActivityId);
            moveActivityIdsContainer.SetCallActivitySubProcessVersion(callActivitySubProcessVersion);
            moveActivityIdList.Add(moveActivityIdsContainer);
            return this;
        }


        public ChangeActivityStateBuilder EnableEventSubProcessStartEvent(string eventSubProcessStartEventId)
        {
            EnableActivityIdContainer enableActivityIdContainer = new EnableActivityIdContainer(eventSubProcessStartEventId);
            enableActivityIdList.Add(enableActivityIdContainer);
            return this;
        }


        public ChangeActivityStateBuilder ProcessVariable(string processVariableName, object processVariableValue)
        {
            if (this.processVariables == null)
            {
                this.processVariables = new Dictionary<string, object>();
            }

            this.processVariables.Add(processVariableName, processVariableValue);
            return this;
        }


        public ChangeActivityStateBuilder ProcessVariables(Dictionary<string, object> processVariables)
        {
            this.processVariables = processVariables;
            return this;
        }


        public ChangeActivityStateBuilder LocalVariable(string startActivityId, string localVariableName, object localVariableValue)
        {
            if (this.localVariables == null)
            {
                this.localVariables = new Dictionary<string, Dictionary<string, object>>();
            }

            Dictionary<string, object> localVariableMap = null;
            if (localVariables.ContainsKey(startActivityId))
            {
                localVariableMap = localVariables[startActivityId];
            }
            else
            {
                localVariableMap = new Dictionary<string, object>();
            }

            localVariableMap.Add(localVariableName, localVariableValue);

            this.localVariables.Add(startActivityId, localVariableMap);

            return this;
        }


        public ChangeActivityStateBuilder LocalVariables(string startActivityId, Dictionary<string, object> localVariables)
        {
            if (this.localVariables == null)
            {
                this.localVariables = new Dictionary<string, Dictionary<string, object>>();
            }

            this.localVariables.Add(startActivityId, localVariables);

            return this;
        }


        public void ChangeState()
        {
            if (runtimeService == null)
            {
                throw new ActivitiException("RuntimeService cannot be null, Obtain your builder instance from the RuntimeService to access this feature");
            }
            runtimeService.ChangeActivityState(this);
        }

        public string GetProcessInstanceId()
        {
            return processInstanceId;
        }

        public List<MoveExecutionIdContainer> GetMoveExecutionIdList()
        {
            return moveExecutionIdList;
        }

        public List<MoveActivityIdContainer> GetMoveActivityIdList()
        {
            return moveActivityIdList;
        }

        public List<EnableActivityIdContainer> GetEnableActivityIdList()
        {
            return enableActivityIdList;
        }

        public Dictionary<string, object> GetProcessInstanceVariables()
        {
            return processVariables;
        }

        public Dictionary<string, Dictionary<string, object>> GetLocalVariables()
        {
            return localVariables;
        }
    }
}
